const fnList = ['onLoad', 'onLoadAsync', 'onReady', 'onShow', 'onShowAsync', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll', 'onTabItemTap'];

const mixinFn = function(config = {}) {
  const app = getApp();
  const fnMap = {};
  const mixins = config.mixins;
  const mixConfig = {
    data: {
      authorization: false,
      windowWidth: 0,
      windowHeight: 0,
      topbarHeight: 0,
      phoneScale: 1,
      menu: {},
      title: {},
      env: '',
      load: false,
      custormTop: 0, // 默认自定义导航高度
      scrollOffset: 0 // 用来做scroll-view的滚动位置，比如 scrollOffset: this.data.scrollOffset - 1 强制置顶
    }
  };

  if (mixins) {
    Reflect.deleteProperty(config, "mixins");
    mixins.forEach(function (part) {
      for (let p in part) {
        const value = part[p];
        if (p === 'data') { // 混入的data
          mixConfig.data = Object.assign({}, mixConfig.data || {}, value || {});
        } else if (fnList.includes(p)) { // 混入的钩子
          if (!fnMap[p]) {
            fnMap[p] = [value];
          }
          else {
            fnMap[p].push(value);
          }
        } else {
          mixConfig[p] = typeof value === 'undefined' ? mixConfig[p] : value; // 混入的其他属性和方法
        }
      }
    });
  }

  // 混入data和其他fnList中没指定的属性
  for (let p in mixConfig) {
    if (p === 'data') {
      config.data = Object.assign({}, mixConfig.data, config.data); // 保证主配置data优先级最高
    } else {
      config[p] = typeof config[p] === 'undefined' ? mixConfig[p] : config[p];
    }
  }

  // 混入fnList中指定的属性
  for (let k in fnMap) {
    const fnList = fnMap[k] || [];
    const fnCfg = config[k];
    config[k] = function (...rest) {
      fnList.forEach(fn => {
        fn.call(this, ...rest);
      });
      if (typeof fnCfg === 'function') {
        fnCfg.call(this, ...rest);
      }
    };
  }

  // 针对onLoad进行特殊处理
  const onLoadFn = config['onLoad'];
  config.onLoad = function (...rest) {
    const pages = getCurrentPages();
    const page = pages.pop();

    this.page = page;
    app.page = page;

    if (typeof onLoadFn === 'function') {
      onLoadFn.call(this, ...rest);
    }

    // 扩展异步onLoad
    const fnCfg = config['onLoadAsync'];
    app.getUserInfoNotice().then(() => {
      if (typeof fnCfg === 'function') {
        fnCfg.call(this, ...rest);
      }
    });
  };

  // 针对onShow进行特殊处理
  const onShowFn = config['onShow'];
  config.onShow = function () {
    const options = this.page.options;

    if (typeof onShowFn === 'function') {
      onShowFn.call(this, options);
    }

    // 扩展异步onShow
    const fnCfg = config['onShowAsync'];
    app.getUserInfoNotice().then(() => {
      if (typeof fnCfg === 'function') {
        fnCfg.call(this, options);
      }
    });
  };

  // 针对onHide进行特殊处理
  const onHideFn = config['onHide'];
  config.onHide = function (options) {
    app.sendLog();
    if (typeof onHideFn === 'function') {
      onHideFn.call(this, options);
    }
  };

  // 针对onUnload进行特殊处理
  const onUnloadFn = config['onUnload'];
  config.onUnload = function (options) {
    app.sendLog();
    if (typeof onUnloadFn === 'function') {
      onUnloadFn.call(this, options);
    }
  };

  config.catchFn = function() {};

  config.onCustormTop = function (e) {
    const { detail: { height, menu }} = e;
    this.setData({
      custormTop: height,
      menu
    })
  };

  config.addEvent = function (type, fn) {
    this.eventObject = this.eventObject || {};
    if (typeof type === 'string') {
      if (!fn) {
        return this;
      } else if (Object.prototype.toString.call(fn) === '[object Array]') {
        fn.forEach((elem, index) => {
          this.addEvent(type, elem);
        });
      } else {
        const types = this.eventObject[type] || [];
        if (types.indexOf(fn) === -1) {
          types.push(fn);
        }

        this.eventObject[type] = types;
      }
    } else {
      for (let t in type) {
        this.addEvent(t, type[t]);
      }
    }
    return this;
  };

  config.fireEvent = function () {
    this.eventObject = this.eventObject || {};
    let type = arguments[0],
      args = Array.prototype.slice.call(arguments, 1),
      events = this.eventObject[type];

    if (!events) {
      return this;
    }
    args = args || [];
    events.forEach((fn) => {
      if (fn.apply(this, args) === false) {
        return false;
      }
    });
    return true;
  };

  config.removeEvent = function (type, fn) {
    this.eventObject = this.eventObject || {};
    if (!type) {
      this.eventObject = {};
    } else if (typeof type === 'string') {
      if (!fn) {
        this.eventObject[type] = [];
      } else {
        const events = this.eventObject[type];
        if (events) {
          let index = events.indexOf(fn);
          if (index !== -1) {
            events.splice(index, 1);
          }
        }
      }
    } else {
      for (let t in type) {
        this.removeEvent(t, type[t]);
      }
    }
    return this;
  };

  return config;
};

export default function(config) {
  config._use_mixin_function = true;  // 页面使用mixin方法的标志
  return mixinFn(config);
};

if (!Page.redefined) {
  console.log('redefined page');
  const pageFn = Page;

  Page = function (config) {
    if (config._use_mixin_function) {
      pageFn(config);
    } else {
      const newConfig = mixinFn(config);
      pageFn(newConfig);
    }
  };

  Page.redefined = true;
}



